#! /usr/bin/python2.4
# jhebert@cs.washington.edu

""" Code for discovering other ChartRunners. """

import time
import Queue
import socket
import random
from util.nodes.GridRepository import GridRepository

def Starter(INPUTS : start, ports):
  """ This should init a couple listeners and the repo. """
  udpPort, tcpPort = ports
  #Ports to listen for communication on.
  emit('UDPlistenPair', (udpPort, socket.SOCK_DGRAM))
  emit('TCPlistenPair', (tcpPort, socket.SOCK_STREAM))
  #Init the GridRepository with port info.
  emit("repo", GridRepository(ports))
  #Force an update and broadcast.
  emit("messages", "")

def Closer(INPUTS : start, exit, ports):
  udpPort, tcpPort = ports
  sock=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  for i in range(10):
    sock.sendto('EXIT', ('',udpPort))
  sock.close()
  sock2=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock2.connect(('', tcpPort))
  sock2.send('EXIT')
  sock2.close()

def UDPListener(INPUT : UDPlistenPair):
  """ This needs to create a socket of the right type and
  listen for messages. """
  port, socketType = UDPlistenPair
  sock = socket.socket(socket.AF_INET, socketType) 
  sock.bind(('', port))
  while 1:
    data, address = sock.recvfrom(1024)
    print 'Received:',data, 'from:', address
    emit('messages', (data,address))
    if(data=='EXIT'):
      return

def TCPListener(INPUT : TCPlistenPair):
  """ This needs to create a socket of the right type and
  listen for messages. """
  port, socketType = TCPlistenPair
  sock = socket.socket(socket.AF_INET, socketType) 
  sock.bind(('', port))
  sock.listen(5)
  while 1:
    conn, address = sock.accept()
    data = conn.recv(1024)
    print 'Received:',data, 'from:', address
    emit('messages', (data,address))
    if(data=='EXIT'):
      return 

def Repo(INPUT : list messages, STATE : repo):
  """ This handler is notified of recieved messages. It should
  track known state of other nodes, broadcast own state and
  notify as needed. """
  repo.Update(messages)
  try:
    while 1:
      message = repo.messagesToSend.get(False)
      emit('sendPair', message)
  except Queue.Empty:
    pass

def Notifier(INPUT : sendPair):
  """ This should send a message to the address. """
  address, message = sendPair
  print 'Sending:', message, 'to address:', address
  timeToSleep = random.random()
  time.sleep(timeToSleep)
  if(address[0]=='255.255.255.255'):
    sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    len=sock.sendto(message, address)
  else:
    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    try:
      sock.connect(address)
      sock.send(message)
    except socket.error, err:
      pass
    sock.close()
      
